#pragma once

#include "pch.h"

#include "Utils/FileUtils.h"

namespace ym
{
    class Shader
    {
    public:
        // 构造器读取并构建着色器
        Shader(const std::filesystem::path vertexShaderFilePath, const std::filesystem::path fragmentShaderFilePath);
        // 使用/激活程序
        void use() const { glUseProgram(this->_id); }
        const unsigned int getID() const { return this->_id; }
        // uniform工具函数
        template <typename T> void setUniformValue(const std::string& name, T value);

    private:
        // 程序ID
        unsigned int _id;
    };

    Shader::Shader(const std::filesystem::path vertexShaderFilePath, const std::filesystem::path fragmentShaderFilePath)
    {
        this->_id = 0;

        int success;
        char infoLog[512];

        auto vsStr = FileUtils::getStringFromFile(vertexShaderFilePath);
        const char* vertexShaderSource = vsStr.c_str();
        auto fsStr = FileUtils::getStringFromFile(fragmentShaderFilePath);
        const char* fragmentShaderSource = fsStr.c_str();

        // 创建顶点着色器
        unsigned int vertexShader;
        vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);

        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            std::cout << "vertexShader compiled failed.\n";
            glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            glDeleteShader(vertexShader);
            return;
        }

        // 创建片段着色器
        unsigned int fragmentShader;
        fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);

        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            std::cout << "fragmentShader compiled failed.\n";
            glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            glDeleteShader(fragmentShader);
            return;
        }

        // 创建着色器程序
        this->_id = glCreateProgram();
        glAttachShader(this->_id, vertexShader);
        glAttachShader(this->_id, fragmentShader);
        glLinkProgram(this->_id);

        glGetProgramiv(this->_id, GL_LINK_STATUS, &success);
        if (!success)
        {
            std::cout << "shaderProgram linked failed.\n";
            glGetProgramInfoLog(this->_id, 512, NULL, infoLog);
            glDeleteProgram(this->_id);
            return;
        }

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    }

    template <typename T> void Shader::setUniformValue(const std::string& name, T value)
    {
        int location = glGetUniformLocation(this->_id, name);
        if (location == -1)
        {
            std::cout << "uniformValue '" << name << "' is not found." << std::endl;
            return;
        }
    }
} // namespace ym